﻿using CRL.Data.LambdaQuery;
using Nest;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Linq.Expressions;

namespace CRL.Elasticsearch
{
    public static class MethodExtension
    {
        public static bool WithIdsQuery<T>(this T origin, IEnumerable<Id> values) where T : class
        {
            return true;
        }
        public static bool WithWildcardQuery(this string field, string value)
        {
            return true;
        }
        public static bool WithTermQuery<T>(this T field, T value)
        {
            return true;
        }
        public static bool WithTermsQuery<T>(this T field, IEnumerable<T> values)
        {
            return true;
        }
        public static bool WithMatchQuery(this string field, string value, Nest.Operator _operator = Nest.Operator.And)
        {
            return true;
        }
        public static bool WithFuzzyQuery(this string field, string value)
        {
            return true;
        }
        public static bool WithMatchPhraseQuery(this string field, string value)
        {
            return true;
        }
        public static bool WithMultiMatchQuery<T>(this T origin, string[] fields, string value, Nest.Operator Operator, TextQueryType textQueryType) where T : class
        {
            return true;
        }
        public static bool WithQueryBase<T>(this T origin, QueryBase queryBase) where T : class
        {
            return true;
        }
        public static bool WithBoolQuery<T>(this ILambdaQuery<T> query, BoolQueryCreater<T> creater) where T : class
        {
            query.Where(b => b.WithQueryBase(creater));
            return true;
        }

        //static List<QueryContainer> getFilter<T>(ESLambdaQuery<T> query,Expression<Func<T, bool>> expression)
        //{
        //    if (expression == null)
        //        return null;
        //    var crlExpression = query.FormatExpression(expression.Body);
        //    var filterData = query.RouteCRLExpression(crlExpression);
        //    return filterData.Filters;
        //}
        public static List<Dictionary<string, long>> ToAggregationCount<T>(this ILambdaQuery<T> query) where T : class
        {
            var result = query.ToDynamic();
            return result.Select(b => (Dictionary<string, long>)b).ToList();
        }
        public static List<Dictionary<string, long>> GetAggregationCount<T>(this ILambdaQuery<T> query) where T : class
        {
            var _query = query as ESLambdaQuery<T>;
            return _query._AggregationCount ?? new List<Dictionary<string, long>>();
        }
        public static void HasChild<T, T2>(this ILambdaQuery<T> query, ILambdaQuery<T2> childQuery) where T : class
    where T2 : class
        {
            var _query = childQuery as ESLambdaQuery<T2>;
            var hasChildQuery = new HasChildQuery
            {
                Name = "child_query",
                Boost = 1.1,
                Type = Infer.Relation<T2>(),
                InnerHits = new InnerHits { Explain = true },
                ScoreMode = ChildScoreMode.Average,
                MinChildren = 0
            };
            hasChildQuery.Query = _query.queryContainers.Count == 1 ? _query.queryContainers.FirstOrDefault() : new BoolQuery { Filter = _query.queryContainers };
            var method = query.GetType().GetMethod("AddQueryBase");
            method.Invoke(query, new object[] { hasChildQuery });
        }
        public static void HasChild<T, T2>(this ILambdaQuery<T> query, ILambdaQuery<T2> childQuery, Expression<Func<T, bool>> parentShould) where T : class
            where T2 : class
        {
            var _query = childQuery as ESLambdaQuery<T2>;
            var hasChildQuery = new HasChildQuery
            {
                Name = "child_query",
                Boost = 1.1,
                Type = Infer.Relation<T2>(),
                InnerHits = new InnerHits { Explain = true },
                ScoreMode = ChildScoreMode.Average,
                MinChildren = 0
            };
            var query2 = query.CreateQuery<T>();
            var _query2 = query2 as ESLambdaQuery<T>;
            query2.Where(parentShould);
            hasChildQuery.Query = _query.queryContainers.Count == 1 ? _query.queryContainers.FirstOrDefault() : new BoolQuery { Filter = _query.queryContainers };
            var childShould = new List<QueryContainer>();
            childShould.Add(hasChildQuery);
            childShould.AddRange(_query2.queryContainers);
            var bq = new BoolQuery()
            {
                Should = childShould
            };
            var method = query.GetType().GetMethod("AddQueryBase");
            method.Invoke(query, new object[] { bq });
        }
        public static void HasParent<T, T2>(this ILambdaQuery<T> query, ILambdaQuery<T2> parentQuery) where T : class
           where T2 : class
        {
            var _query = parentQuery as ESLambdaQuery<T2>;
            var hasParentQuery = new HasParentQuery
            {
                Name = "parent_query",
                Boost = 1.1,
                ParentType = Infer.Relation<T2>(),
                InnerHits = new InnerHits { Explain = true },
                Score = true,
                IgnoreUnmapped = true
            };
            hasParentQuery.Query = _query.queryContainers.Count == 1 ? _query.queryContainers.FirstOrDefault() : new BoolQuery { Filter = _query.queryContainers };
            var method = query.GetType().GetMethod("AddQueryBase");
            method.Invoke(query, new object[] { hasParentQuery });
        }
        public static IReadOnlyCollection<AnalyzeToken> Analyze<T>(this ILambdaQuery<T> query, string txt, string analyser)
        {
            var _query = query as ESLambdaQuery<T>;
            return _query.Analyze(txt, analyser);
        }
        public static ILambdaQuery<T> Highlight<T, TResult>(this ILambdaQuery<T> query, Expression<Func<T, TResult>> field, string preTags = "<em>", string postTags = "</em>", Action<Highlight> option = null)
        {
            var mExp = field.Body as MemberExpression;
            if (mExp == null)
            {
                throw new Exception("必须为 MemberExpression");
            }
            var _query = query as ESLambdaQuery<T>;
            if (_query.Highlight == null)
            {
                _query.Highlight = new Highlight()
                {
                    RequireFieldMatch = false, // 如果你想在所有字段中高亮匹配项，可以将其设为false
                    Encoder = HighlighterEncoder.Default,
                    Fields = new Dictionary<Field, IHighlightField>()
                };
                option?.Invoke(_query.Highlight);
            }
            _query.Highlight.Fields.Add(mExp.Member.Name, new HighlightField { PreTags = new string[] { preTags }, PostTags = new string[] { postTags } });
            return query;
        }
    }
}
